﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Threading;

namespace Pixysoft.Framework.Logs.Core
{
    internal static class SingletonLogger
    {
        private static readonly System.Threading.ReaderWriterLock locker = new ReaderWriterLock();

        /// <summary>
        /// 是否存在文件
        /// </summary>
        /// <param name="path"></param>
        /// <param name="filename"></param>
        /// <returns></returns>
        public static bool HasFile(string path, string filename, string postfix)
        {
            return File.Exists(GetFileName(path, filename, postfix));
        }


        /// <summary>
        /// 直接写入
        /// </summary>
        /// <param name="path"></param>
        /// <param name="filename"></param>
        /// <param name="content"></param>
        /// <returns></returns>
        public static string Write(string path, string filename, string postfix, string content)
        {
            if (string.IsNullOrEmpty(content))
                return null;

            if (string.IsNullOrEmpty(path))
                return null;

            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }

            string pathfilename = GetFileName(path, filename, postfix);

            return Write(pathfilename, content);
        }

        /// <summary>
        /// 直接写入
        /// </summary>
        /// <param name="path"></param>
        /// <param name="filename"></param>
        /// <param name="content"></param>
        /// <returns></returns>
        public static string Write(string pathfilename, string content)
        {
            if (string.IsNullOrEmpty(pathfilename))
                return null;

            locker.AcquireWriterLock(Timeout.Infinite);

            try
            {
                using (FileStream sw = File.Open(pathfilename, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
                {
                    StreamWriter writer = new StreamWriter(sw, Encoding.UTF8);

                    writer.Write(content);

                    writer.Flush();

                    writer.Close();

                    writer.Dispose();
                }
            }
            finally
            {
                locker.ReleaseWriterLock();
            }

            return content;

        }

        /// <summary>
        /// 直接写入
        /// </summary>
        /// <param name="path"></param>
        /// <param name="filename"></param>
        /// <param name="content"></param>
        /// <returns></returns>
        public static byte[] Write(string pathfilename, byte[] content)
        {
            if (string.IsNullOrEmpty(pathfilename))
                return null;

            locker.AcquireWriterLock(Timeout.Infinite);

            try
            {
                using (FileStream sw = File.Open(pathfilename, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
                {
                    sw.Write(content, 0, content.Length);

                    sw.Flush();

                    sw.Close();

                    sw.Dispose();
                }
            }
            finally
            {
                locker.ReleaseWriterLock();
            }

            return content;

        }


        /// <summary>
        /// 追加内容
        /// </summary>
        /// <param name="path"></param>
        /// <param name="filename"></param>
        /// <param name="?"></param>
        /// <returns></returns>
        public static string Insert(string path, string filename, string postfix, string content)
        {
            if (string.IsNullOrEmpty(content))
                return null;

            if (string.IsNullOrEmpty(path))
                return null;

            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }

            string pathfilename = GetFileName(path, filename, postfix);

            locker.AcquireWriterLock(Timeout.Infinite);

            try
            {
                //http://stackoverflow.com/questions/124946/c-file-read-write-fileshare-doesnt-appear-to-work

                //09-11-30 fileshare应该是readwrite 

                using (FileStream sw = File.Open(pathfilename, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite))
                {
                    sw.Seek(0, SeekOrigin.Begin);

                    StreamWriter writer = new StreamWriter(sw, Encoding.UTF8);

                    writer.Write(content);

                    writer.Flush();

                    writer.Close();

                    writer.Dispose();
                }
            }
            finally
            {
                locker.ReleaseWriterLock();
            }


            AutoBackup(path, filename, postfix, false);

            return content;
        }

        /// <summary>
        /// 添加内容 线程安全
        /// </summary>
        /// <param name="path"></param>
        /// <param name="filename"></param>
        /// <param name="content"></param>
        public static byte[] Insert(string path, string filename, string postfix, byte[] content)
        {
            if (content == null)
                return null;

            if (string.IsNullOrEmpty(path))
                return null;

            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }

            string pathfilename = GetFileName(path, filename, postfix);

            locker.AcquireWriterLock(Timeout.Infinite);

            try
            {
                using (FileStream sw = File.Open(pathfilename, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite))
                {
                    sw.Seek(0, SeekOrigin.Begin);

                    sw.Write(content, 0, content.Length);

                    sw.Close();

                    sw.Dispose();
                }
            }
            finally
            {
                locker.ReleaseWriterLock();
            }


            AutoBackup(path, filename, postfix, false);

            return content;
        }


        /// <summary>
        /// 追加内容
        /// </summary>
        /// <param name="path"></param>
        /// <param name="filename"></param>
        /// <param name="?"></param>
        /// <returns></returns>
        public static string Append(string path, string filename, string postfix, string content)
        {
            return Append(path, filename, postfix, content, false);
        }

        /// <summary>
        /// 追加内容
        /// </summary>
        /// <param name="path"></param>
        /// <param name="filename"></param>
        /// <param name="?"></param>
        /// <returns></returns>
        public static string Append(string path, string filename, string postfix, string content, bool directArchive)
        {
            if (string.IsNullOrEmpty(content))
                return null;

            if (string.IsNullOrEmpty(path))
                return null;

            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }

            string pathfilename = GetFileName(path, filename, postfix);

            locker.AcquireWriterLock(Timeout.Infinite);

            try
            {
                //http://stackoverflow.com/questions/124946/c-file-read-write-fileshare-doesnt-appear-to-work

                //09-11-30 fileshare应该是readwrite 

                using (FileStream sw = File.Open(pathfilename, FileMode.Append, FileAccess.Write, FileShare.ReadWrite))
                {
                    StreamWriter writer = new StreamWriter(sw, Encoding.UTF8);

                    writer.Write(content);

                    writer.Flush();

                    writer.Close();

                    writer.Dispose();
                }
            }
            finally
            {
                locker.ReleaseWriterLock();
            }

            AutoBackup(path, filename, postfix, directArchive);

            return content;
        }

        /// <summary>
        /// 添加内容 线程安全
        /// </summary>
        /// <param name="path"></param>
        /// <param name="filename"></param>
        /// <param name="content"></param>
        public static byte[] Append(string path, string filename, string postfix, byte[] content)
        {
            return Append(path, filename, postfix, content, false);
        }

        /// <summary>
        /// 添加内容 线程安全
        /// </summary>
        /// <param name="path"></param>
        /// <param name="filename"></param>
        /// <param name="content"></param>
        public static byte[] Append(string path, string filename, string postfix, byte[] content, bool directArchive)
        {
            if (content == null)
                return null;

            if (string.IsNullOrEmpty(path))
                return null;

            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }

            string pathfilename = GetFileName(path, filename, postfix);

            locker.AcquireWriterLock(Timeout.Infinite);

            try
            {
                using (FileStream sw = File.Open(pathfilename, FileMode.Append, FileAccess.Write, FileShare.ReadWrite))
                {
                    sw.Write(content, 0, content.Length);

                    sw.Close();

                    sw.Dispose();
                }
            }
            finally
            {
                locker.ReleaseWriterLock();
            }

            AutoBackup(path, filename, postfix, directArchive);

            return content;
        }

        /// <summary>
        /// 读取内容 线程安全
        /// </summary>
        /// <param name="path"></param>
        /// <param name="filename"></param>
        /// <returns></returns>
        public static string Read(string path, string filename, string postfix)
        {
            if (string.IsNullOrEmpty(path))
                return null;

            if (string.IsNullOrEmpty(filename))
                return null;

            if (!Directory.Exists(path))
            {
                return null;
            }

            string pathfilename = GetFileName(path, filename, postfix);

            return Read(pathfilename);
        }

        /// <summary>
        /// 读取内容 线程安全
        /// </summary>
        /// <param name="path"></param>
        /// <param name="filename"></param>
        /// <returns></returns>
        public static string Read(string pathfilename)
        {
            if (string.IsNullOrEmpty(pathfilename))
                return null;

            locker.AcquireReaderLock(Timeout.Infinite);

            try
            {
                if (!File.Exists(pathfilename))
                {
                    return null;
                }

                string content = null;

                using (FileStream sw = File.Open(pathfilename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                {
                    StreamReader reader = new StreamReader(sw);

                    content = reader.ReadToEnd();

                    reader.Close();

                    reader.Dispose();
                }

                return content;
            }
            finally
            {
                locker.ReleaseReaderLock();
            }
        }

        /// <summary>
        /// 对文件进行备份 如果文件不存在 则跳开
        /// </summary>
        /// <param name="path"></param>
        /// <param name="filename"></param>
        /// <returns></returns>
        public static bool Backup(string path, string filename, string postfix)
        {
            if (string.IsNullOrEmpty(path))
                return false;

            if (string.IsNullOrEmpty(filename))
                return false;

            if (!Directory.Exists(path))
            {
                return false;
            }

            string pathfilename = GetFileName(path, filename, postfix);

            locker.AcquireWriterLock(Timeout.Infinite);

            try
            {
                if (!File.Exists(pathfilename))
                {
                    return false;
                }

                FileInfo info = new FileInfo(pathfilename);

                string backfilename = null;

                while (true)
                {
                    backfilename = GetBakFileName(path, filename, postfix);

                    if (File.Exists(backfilename))
                        continue;

                    break;
                }

                //http://bytes.com/topic/net/answers/486309-rename-file-c

                //09-11-30 使用moveto，不要copyto

                info.MoveTo(backfilename);

                return true;
            }
            finally
            {
                locker.ReleaseWriterLock();
            }
        }

        private static bool AutoBackup(string path, string filename, string postfix, bool directArchive)
        {
            string pathfilename = GetFileName(path, filename, postfix);

            locker.AcquireWriterLock(Timeout.Infinite);

            try
            {
                if (!File.Exists(pathfilename))
                    return false;

                FileInfo info = new FileInfo(pathfilename);

                long length = info.Length;

                if (length > StringHelper.log_capacity || directArchive)
                {
                    string backfilename = null;

                    while (true)
                    {
                        backfilename = GetBakFileName(path, filename, postfix);

                        if (File.Exists(backfilename))
                            continue;

                        break;
                    }

                    //http://bytes.com/topic/net/answers/486309-rename-file-c

                    //09-11-30 使用moveto，不要copyto

                    info.MoveTo(backfilename);
                }

                return true;
            }
            finally
            {
                locker.ReleaseWriterLock();
            }
        }

        private static string GetFileName(string path, string filename, string postfix)
        {
            if (!path.EndsWith(@"\"))
                return path + @"\" + filename + postfix;
            else
                return path + filename + postfix;
        }

        private static string GetBakFileName(string path, string filename, string postfix)
        {
            if (!path.EndsWith(@"\"))
                return path + @"\" + filename + "." + Pixysoft.Tools.GlobalTimer.Instance.GetGlobalTimeSequence() + postfix;
            else
                return path + filename + "." + Pixysoft.Tools.GlobalTimer.Instance.GetGlobalTimeSequence() + postfix;
        }
    }
}
